﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyAlbum.Model;
using MyAlbum.Utility;
using PersonalAlbum;
using MyAlbum.DataAccess.LinqToSql;


namespace MyAlbum.Data.Linq
{
    public class EntryRepository : IEntryRepository
    {

        private string _connectionString;
        public EntryRepository(string connectionString)
        {
            Assert.IsNotNull(connectionString);
            this._connectionString = connectionString;

        }

        /// <summary>
        /// Add a new tag if the tag does not exist, else increase it's count. 
        /// Add a new relation if non was found.
        /// </summary>
        /// <param name="entryId">The entry id</param>
        /// <param name="tags">The tag name</param>   
        public void AddTagsForEntry(string entryId, string tagName)
        {
            Assert.IsNotNull(tagName);
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                Tag t = ImagesDB.Tags.FirstOrDefault(s => s.Name == tagName.Trim());
                if (t == null)
                {
                    t = new Tag();
                    t.Name = tagName.Trim();
                    t.Count = 0;
                    ImagesDB.Tags.InsertOnSubmit(t);
                    ImagesDB.SubmitChanges();//so we'll get a tag id

                }
                t.Count++;
                TagEntryRelation te = ImagesDB.TagEntryRelations.FirstOrDefault(s => s.TagId == t.Id && s.EntryId ==new Guid( entryId));
                if (te == null)
                {
                    te = new TagEntryRelation() { EntryId = new Guid(entryId), TagId = t.Id };
                    ImagesDB.TagEntryRelations.InsertOnSubmit(te);
                }
                ImagesDB.SubmitChanges();
            }
        }




        public List<MyAlbum.Model.Entry> GetItems(int pageNumber, int count, bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                var entriesResult = LoadItems(ImagesDB, ImagesDB.Entries.Where(e => (visible ? e.Visible : true)).Skip((pageNumber - 1) * count).Take(count),true);
                return entriesResult.ToList();
            }
        }

        public List<MyAlbum.Model.Entry> GetItems()
        {
            return GetItems(1, int.MaxValue, true);
        }
        /// <summary>
        /// Load random visible entries summary (no replies or tags)
        /// </summary>
        /// <param name="count">The max number of entries to load</param>
        /// <returns>List of Entry</returns>
        public List<MyAlbum.Model.Entry> LoadRandomEntriesSummary(int count)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                if (count <= 0)
                {
                    return new List<MyAlbum.Model.Entry>();
                }
                else
                {
                    var entries = ImagesDB.Entries.Where(e => e.Visible);
                    int maxSkip = Math.Max(0, entries.Count() - count);
                    return (LoadItems(ImagesDB, entries.Skip(new Random().Next(maxSkip)).Take(count), false).ToList());
                }
            }
        }


        private IEnumerable<MyAlbum.Model.Entry> LoadItems(DataClasses1DataContext ImagesDB, IQueryable<Entry> objectQuery, bool withTagsAndReplies)
        {
            return objectQuery.Select(e =>
                new MyAlbum.Model.Entry()
                {
                    ParentId = e.ParentId.GetValueOrDefault().ToString(),
                    Description = e.Description,
                    EntryType = e.EntryType.GetValueOrDefault(),
                    FileSize = e.FileSize.GetValueOrDefault(),
                    Height = e.Height.GetValueOrDefault(),
                    Id = e.Id.ToString(),
                    Title = e.Title,
                    Uri = e.Uri,
                    VideoLen = e.VideoLen.GetValueOrDefault(),
                    Visible = e.Visible,
                    Width = e.Width.GetValueOrDefault(),
                    Date = e.Date,
                    ThumbHeight = e.ThumbHeight.GetValueOrDefault(),
                    ThumbUri = e.ThumbURI,
                    ThumbWidth = e.ThumbWidth.GetValueOrDefault(),
                    Tags = (withTagsAndReplies ? from r in ImagesDB.TagEntryRelations
                                                 join t in ImagesDB.Tags on r.TagId equals t.Id
                                                 where r.EntryId == e.Id
                                                 select new MyAlbum.Model.Tag()
                                                 {
                                                     Count = t.Count,
                                                     Id = t.Id.ToString(),
                                                     Name = t.Name
                                                 } : null),
                    Replies = (withTagsAndReplies ? from r in ImagesDB.Replies
                                                    where r.EntryId == e.Id
                                                    select new MyAlbum.Model.Reply()
                                                    {
                                                        Id = r.Id.ToString(),
                                                        Email = r.Email,
                                                        EntryId = r.EntryId.ToString(),
                                                        Body = r.Body,
                                                        IsApproved = r.Approved,
                                                        Subject = r.Subject,
                                                        TimeStamp = r.Timestamp,
                                                        UserName = r.Username
                                                    } : null)

                });

        }


        public List<MyAlbum.Model.Entry> GetEntriesByTagName(string tagName, bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                var entries = ImagesDB.Entries;
                var relations = ImagesDB.TagEntryRelations;
                var tags = ImagesDB.Tags;
                IQueryable<MyAlbum.Data.Linq.Entry> items = from r in relations
                                                                  join e in entries on r.EntryId equals e.Id
                                                                  join t in tags on r.TagId equals t.Id
                                                                  where t.Name.Contains(tagName.Trim()) && (visible ? e.Visible : true)
                                                                  select e;
                var entriesResult = LoadItems(ImagesDB, items,true);
                return entriesResult.ToList();
            }
        }

        public void AddItem(MyAlbum.Model.Entry item)
        {
            Assert.IsNotNull(item);
            Assert.IsNotNull(item.Title);
            Entry e = new Entry()
            {
                Id=Guid.NewGuid(),
                Width = item.Width,
                Visible = item.Visible,
                VideoLen = item.VideoLen,
                Uri = item.Uri,
                Title = item.Title,
                Height = item.Height,
                FileSize = item.FileSize,
                EntryType = item.EntryType,
                Description = item.Description,
                ParentId =new Guid( item.ParentId),
                Date = item.Date,
                ThumbWidth = item.ThumbWidth,
                ThumbURI = item.ThumbUri,
                ThumbHeight = item.ThumbHeight
            };
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                ImagesDB.Entries.InsertOnSubmit(e);
                ImagesDB.SubmitChanges();
            }
            item.Id = e.Id.ToString();
            AddTags(item);
        }

        private void AddTags(MyAlbum.Model.Entry item)
        {
            Assert.IsNotNull(item);
            
            if (item.Tags != null)
            {
                foreach (var tag in item.Tags)
                {
                    AddTagsForEntry(item.Id, tag.Name);
                }
            }
        }

        public void DeleteItem(MyAlbum.Model.Entry item)
        {
            Assert.IsNotNull(item);
            
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                var old = ImagesDB.Entries.FirstOrDefault(e => e.Id == new Guid(item.Id));
                if (old != null)
                {
                    ImagesDB.Entries.DeleteOnSubmit(old);
                    RemoveTagsForEntry(item.Id);
                    ImagesDB.SubmitChanges();

                }
            }
        }

        /// <summary>
        /// Removes all of the relations of the specified entry, 
        /// and decreases the count all of the relevant tags
        /// </summary>
        /// <param name="entryId">The entry id</param>
        public void RemoveTagsForEntry(string entryId)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                var relations = ImagesDB.TagEntryRelations.Where(s => s.EntryId ==new Guid( entryId));
                foreach (var item in relations)
                {
                    var t = ImagesDB.Tags.FirstOrDefault(s => s.Id == item.TagId);
                    if (t != null)
                    {
                        if (t.Count > 1)
                        {
                            t.Count--;
                        }
                        else
                        {
                            ImagesDB.Tags.DeleteOnSubmit(t);
                        }
                    }
                    ImagesDB.TagEntryRelations.DeleteOnSubmit(item);
                }
                ImagesDB.SubmitChanges();
            }
        }

        public void UpdateItem(MyAlbum.Model.Entry item)
        {
            Assert.IsNotNull(item);
            Assert.IsNotNull(item.Title);
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                var old = ImagesDB.Entries.FirstOrDefault(e => e.Id ==new Guid( item.Id));
                if (old != null)
                {
                    old.Description = item.Description;
                    old.Visible = item.Visible;
                    old.ParentId =new Guid( item.ParentId);
                    old.EntryType = item.EntryType;
                    old.FileSize = item.FileSize;
                    old.Height = item.Height;
                    old.Title = item.Title;
                    old.Uri = item.Uri;
                    old.VideoLen = item.VideoLen;
                    old.Width = item.Width;
                    old.ThumbHeight = item.ThumbHeight;
                    old.ThumbWidth = item.ThumbWidth;
                    old.ThumbURI = item.ThumbUri;

                    RemoveTagsForEntry(old.Id.ToString());
                    AddTags(item);

                    ImagesDB.SubmitChanges();
                }
            }

        }
        public MyAlbum.Model.Entry GetItemById(string entryId)
        {
            return this.GetEntryById(entryId, true);
        }

        public MyAlbum.Model.Entry GetEntryById(string entryId, bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                return (from e in ImagesDB.Entries
                        where e.Id ==new Guid( entryId) && (visible ? e.Visible : true)
                        select new MyAlbum.Model.Entry()
                        {
                             ParentId = e.ParentId.GetValueOrDefault().ToString(),
                            Description = e.Description,
                            EntryType = e.EntryType.GetValueOrDefault(),
                            FileSize = e.FileSize.GetValueOrDefault(),
                            Height = e.Height.GetValueOrDefault(),
                            Id = e.Id.ToString(),
                            Title = e.Title,
                            Uri = e.Uri,
                            VideoLen = e.VideoLen.GetValueOrDefault(),
                            Visible = e.Visible,
                            Width = e.Width.GetValueOrDefault(),
                            Date = e.Date,
                            ThumbHeight = e.ThumbHeight.GetValueOrDefault(),
                            ThumbUri = e.ThumbURI,
                            ThumbWidth = e.ThumbWidth.GetValueOrDefault(),
                            Tags = from r in ImagesDB.TagEntryRelations
                                   join t in ImagesDB.Tags on r.TagId equals t.Id
                                   where r.EntryId == e.Id
                                   select new MyAlbum.Model.Tag()
                                   {
                                       Count = t.Count,
                                       Id = t.Id.ToString(),
                                       Name = t.Name
                                   },
                            Replies = from r in ImagesDB.Replies
                                      where r.EntryId == e.Id
                                      select new MyAlbum.Model.Reply()
                                      {
                                          Id = r.Id.ToString(),
                                          Email = r.Email,
                                          EntryId = r.EntryId.ToString(),
                                          Body = r.Body,
                                          IsApproved = r.Approved,
                                          Subject = r.Subject,
                                          TimeStamp = r.Timestamp,
                                          UserName = r.Username
                                      }
                        }).SingleOrDefault();
            }
        }

        public List<MyAlbum.Model.Entry> GetEntriesByAlbum(string parentId, int pageNumber, int count, bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                return LoadItems(ImagesDB, ImagesDB.Entries.Where(e => e.ParentId == new Guid(parentId) && (visible ? e.Visible : true)).Skip((pageNumber - 1) * count).Take(count),true).ToList();
            }
        }


        #region IEntryRepository Members

        public int GetEntriesCount(bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                if (visible)
                {
                    return ImagesDB.Entries.Count(e => e.Visible);
                }
                else
                {
                    return ImagesDB.Entries.Count();
                }
            }
        }

        /// <summary>
        /// Load the latest entries
        /// </summary>
        /// <param name="count">The number of entries to load</param>
        /// <returns>List of Entry</returns>
        public List<MyAlbum.Model.Entry> GetLatestEntries(int count, bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                return (from e in ImagesDB.Entries
                        where (visible ? e.Visible : true)
                        orderby e.Id descending
                        select new MyAlbum.Model.Entry()
                        {
                            ParentId = e.ParentId.GetValueOrDefault().ToString(),
                            Description = e.Description,
                            EntryType = e.EntryType.GetValueOrDefault(),
                            FileSize = e.FileSize.GetValueOrDefault(),
                            Height = e.Height.GetValueOrDefault(),
                            Id = e.Id.ToString(),
                            Title = e.Title,
                            Uri = e.Uri,
                            VideoLen = e.VideoLen.GetValueOrDefault(),
                            Visible = e.Visible,
                            Width = e.Width.GetValueOrDefault(),
                            Date = e.Date,
                            ThumbHeight = e.ThumbHeight.GetValueOrDefault(),
                            ThumbUri = e.ThumbURI,
                            ThumbWidth = e.ThumbWidth.GetValueOrDefault(),
                            Tags = from r in ImagesDB.TagEntryRelations
                                   join t in ImagesDB.Tags on r.TagId equals t.Id
                                   where r.EntryId == e.Id
                                   select new MyAlbum.Model.Tag()
                                   {
                                       Count = t.Count,
                                       Id = t.Id.ToString(),
                                       Name = t.Name
                                   },
                            Replies = from r in ImagesDB.Replies
                                      where r.EntryId == e.Id
                                      select new MyAlbum.Model.Reply()
                                      {
                                          Id = r.Id.ToString(),
                                          Email = r.Email,
                                          EntryId = r.EntryId.ToString(),
                                          Body = r.Body,
                                          IsApproved = r.Approved,
                                          Subject = r.Subject,
                                          TimeStamp = r.Timestamp,
                                          UserName = r.Username
                                      }
                        }).Take(count).ToList();
            }
        }

        public MyAlbum.Model.Entry GetLatestEntry(bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                return (from e in ImagesDB.Entries
                        where (visible ? e.Visible : true) orderby e.Id descending
                        select new MyAlbum.Model.Entry()
                        {
                            ParentId = e.ParentId.GetValueOrDefault().ToString(),
                            Description = e.Description,
                            EntryType = e.EntryType.GetValueOrDefault(),
                            FileSize = e.FileSize.GetValueOrDefault(),
                            Height = e.Height.GetValueOrDefault(),
                            Id = e.Id.ToString(),
                            Title = e.Title,
                            Uri = e.Uri,
                            VideoLen = e.VideoLen.GetValueOrDefault(),
                            Visible = e.Visible,
                            Width = e.Width.GetValueOrDefault(),
                            Date = e.Date,
                            ThumbHeight = e.ThumbHeight.GetValueOrDefault(),
                            ThumbUri = e.ThumbURI,
                            ThumbWidth = e.ThumbWidth.GetValueOrDefault(),
                            Tags = from r in ImagesDB.TagEntryRelations
                                   join t in ImagesDB.Tags on r.TagId equals t.Id
                                   where r.EntryId == e.Id
                                   select new MyAlbum.Model.Tag()
                                   {
                                       Count = t.Count,
                                       Id = t.Id.ToString(),
                                       Name = t.Name
                                   },
                            Replies = from r in ImagesDB.Replies
                                      where r.EntryId == e.Id
                                      select new MyAlbum.Model.Reply()
                                      {
                                          Id = r.Id.ToString(),
                                          Email = r.Email,
                                          EntryId = r.EntryId.ToString(),
                                          Body = r.Body,
                                          IsApproved = r.Approved,
                                          Subject = r.Subject,
                                          TimeStamp = r.Timestamp,
                                          UserName = r.Username
                                      }
                        }).FirstOrDefault();
            }
        }

        public List<MonthSummary> GetEntriesByMonthsSummary(bool visible)
        {
            Func<Entry, bool> filter;
            if (visible)
            {
                filter = e => (bool)e.Visible;

            }
            else
            {
                filter = e => true;
            }
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                return (from e in ImagesDB.Entries.Where(filter)
                        group e by
                        new { e.Date.Year, e.Date.Month } into g
                        orderby g.Key.Year, g.Key.Month
                        select new MonthSummary { Month = g.Key.Month, Year = g.Key.Year, Count = g.Count() }).ToList();
            }
        }

        #endregion

        #region IEntryRepository Members


        public int CountItems(bool visible)
        {
            using (var ImagesDB = new DataClasses1DataContext(this._connectionString))
            {
                return ImagesDB.Entries.Count();
            }
        }

        #endregion
    }
}
